﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using NetSurveillance.WebApp.DataServices.Models;
using NetSurveillance.WebApp.Models;
using NetSurveillance.WebApp.Utilities;
using Newtonsoft.Json;

namespace NetSurveillance.WebApp.Controllers
{
    public class SetupWizardController : BaseController
    {
        private readonly string[] _steps = new[]
            {
                "", "", Resources.MenuResource.Two, Resources.MenuResource.Three,
                Resources.MenuResource.Four
            };
        private int StepIndex
        {
            get
            {
                var stepIndex = DataContainer.Read<int?>(PresetValues.SessionKeys.SetupWizardStep);
                return stepIndex ?? 0;
            }
            set { DataContainer.Add(PresetValues.SessionKeys.SetupWizardStep, value); }
        }
        private string Step
        {
            get { return _steps[StepIndex]; }
        }

        protected override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            base.OnActionExecuting(filterContext);
            var runningTask = DataProvider.TaskService.GetAllModels(false,
                                                                    p => p.TaskStatus == TaskStatusType.Running ||
                                                                    p.TaskStatus == TaskStatusType.Suspend);
            if (runningTask != null && runningTask.Any())
            {
                TempData[PresetValues.TempDataKeys.ErrorMessage] = Resources.MessageResource.HasRunningTask;
                if (Request.UrlReferrer != null)
                    filterContext.Result = new RedirectResult(Request.UrlReferrer.ToString());
                RedirectToAction("Index", "Home");
            }
        }
        protected override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            base.OnActionExecuted(filterContext);
            ViewBag.CurrentMainMenu = 2;
        }

        public ActionResult NetAccessType()
        {
            var setupWizard =
                DataContainer.Read<SetupWizard>(PresetValues.SessionKeys.SetupWizard)
                ?? new SetupWizard {CreateUserId = CurrentUser.Id};
            return View(setupWizard);
        }

        [HttpPost]
        public ActionResult NetAccessType(SetupWizard setupWizard)
        {
            if(ModelState.IsValid)
            {
                DataContainer.Add(PresetValues.SessionKeys.SetupWizard, setupWizard);
                StepIndex = 2;
                if (setupWizard.LineType == "importPcap")
                {
                    setupWizard.IpSettingId = null;
                    return RedirectToAction("PcapUpload");
                }
                if ((setupWizard.LineType == "ytw" && "panglu,arp,chuanjie".Contains(setupWizard.LineMethod))
                    || (setupWizard.LineType == "gx" && "panglu,arp".Contains(setupWizard.LineMethod))
                    || (setupWizard.LineType == "wifi" && setupWizard.LineMethod == "arp"))
                    return RedirectToAction("ServerIpSetting");

                setupWizard.IpSettingId = null;
                return RedirectToAction("CaseAndTask");
            }
            ModelState.AddModelError("", Resources.MessageResource.Save_Error);
            return View(setupWizard);
        }

        [HttpPost]
        public ActionResult LoadNetTypeTip(string lineType, string lineMethod)
        {
            string absPath =
                Path.Combine(Url.Content("~/Views/SetupWizard/"),
                             string.Format("{0}_{1}.html", lineType, lineMethod));
            string fullPath = Server.MapPath(absPath);
            if (System.IO.File.Exists(fullPath))
                return File(fullPath, System.Net.Mime.MediaTypeNames.Text.Plain);
            return new HttpNotFoundResult();
        }

        public ActionResult PcapUpload()
        {
            ViewBag.Step = Step;
            return View();
        }

        [HttpPost]
        public ActionResult PcapUpload(HttpPostedFileBase pcapFile)
        {
            //var pcapFile = Request.Files["PcapFile"];
            if(ModelState.IsValid && pcapFile != null)
            {
                string savePath = Server.MapPath(PresetValues.PcapSavePath);
                var savePathDir = new DirectoryInfo(savePath);
                if(!savePathDir.Exists)
                    savePathDir.Create();
                string saveFullPath = Path.Combine(savePath, pcapFile.FileName);
                pcapFile.SaveAs(saveFullPath);
                var setupWizard = DataContainer.Read<SetupWizard>(PresetValues.SessionKeys.SetupWizard);
                if (setupWizard != null)
                    setupWizard.PcapPath = saveFullPath;
                DataContainer.Add(PresetValues.SessionKeys.SetupWizard, setupWizard);
                StepIndex += 1;
                return RedirectToAction("CaseAndTask");
            }
            ViewBag.Step = Step;
            ModelState.AddModelError("", Resources.MessageResource.Save_Error);
            return View();
        }

        public ActionResult ServerIpSetting()
        {
            var setupWizard = DataContainer.Read<SetupWizard>(PresetValues.SessionKeys.SetupWizard);
            var ipSetting = setupWizard != null && setupWizard.IpSettingId.HasValue && setupWizard.IpSettingId.Value != 0
                                ? DataProvider.IpSettingService.GetModelById(setupWizard.IpSettingId.Value)
                                : DataProvider.IpSettingService.GetLastIpSetting(PresetValues.NetWorkCardName);
            ViewBag.Step = Step;
            return View(ipSetting);
        }

        [HttpPost]
        public ActionResult ServerIpSetting(IpSetting ipSetting, string preSubmit)
        {
            string nextAction = "CaseAndTask";
            if (ModelState.IsValid)
            {
                var serviceResult = DataProvider.IpSettingService.Save(ipSetting);
                var setupWizard = DataContainer.Read<SetupWizard>(PresetValues.SessionKeys.SetupWizard);
                if (serviceResult.ExecutedSuccess && setupWizard != null)
                {
                    var setServerIpEle = ActionXmlUtility.Instance.CreateSetServerIpElement(ipSetting);
                    var actionEle =
                        ActionXmlUtility.Instance.GeneratorActionXml(
                            ActionXmlUtility.Instance.CreateActionRootElement(), setServerIpEle);
                    if (Connector.SendAction(actionEle, PresetValues.MonitorIp, PresetValues.MonitorPort))
                    {
                        setupWizard.IpSettingId = ipSetting.Id;
                        DataContainer.Add(PresetValues.SessionKeys.SetupWizard, setupWizard);
                        
                        if (string.IsNullOrWhiteSpace(preSubmit))
                        {
                            StepIndex += 1;
                            return RedirectToAction(nextAction);
                        }
                    }
                    ModelState.AddModelError("", Resources.MessageResource.SendActionError);
                }
            }
            if (!string.IsNullOrWhiteSpace(preSubmit))
            {
                nextAction = "NetAccessType";
                StepIndex -= 1;
                return RedirectToAction(nextAction);
            }
            ViewBag.Step = Step;
            ModelState.AddModelError("",Resources.MessageResource.Save_Error);
            return View(ipSetting);
        }

        public ActionResult CaseAndTask()
        {
            var cases = DataProvider.CaseService.GetAllModels();
            ViewData["CaseId"] = DataContainer.Read<long>(PresetValues.SessionKeys.SetupWizardCaseId);
            ViewData["TaskName"] = DataContainer.Read<string>(PresetValues.SessionKeys.SetupWizardTaskName);
            ViewBag.Step = Step;
            return View(cases);
        }

        [HttpPost]
        public ActionResult CaseAndTask(long? caseId, string taskName, string preSubmit)
        {
            if (caseId.HasValue)
            {
                if (string.IsNullOrWhiteSpace(taskName))
                    taskName = string.Format("{0:yyyy-MM-dd-HHmmss}", DateTime.Now);
                DataContainer.Add(PresetValues.SessionKeys.SetupWizardCaseId, caseId.Value);
                DataContainer.Add(PresetValues.SessionKeys.SetupWizardTaskName, taskName);
                if (string.IsNullOrWhiteSpace(preSubmit))
                {
                    StepIndex += 1;
                    return RedirectToAction("KeywordSetting");
                }
            }
            if (!string.IsNullOrWhiteSpace(preSubmit))
            {
                var setupWizard = DataContainer.Read<SetupWizard>(PresetValues.SessionKeys.SetupWizard);
                StepIndex -= 1;
                return RedirectToAction(setupWizard.IpSettingId.HasValue && setupWizard.IpSettingId.Value != 0
                                            ? "ServerIpSetting"
                                            : "NetAccessType");
            }
            ModelState.AddModelError("", Resources.MessageResource.Save_Error);
            ViewData["CaseId"] = DataContainer.Read<long>(PresetValues.SessionKeys.SetupWizardCaseId);
            ViewData["TaskName"] = DataContainer.Read<string>(PresetValues.SessionKeys.SetupWizardTaskName);
            ViewBag.Step = Step;
            return View(DataProvider.CaseService.GetAllModels());
        }

        public ActionResult KeywordSetting()
        {
            LoadKeywordSettingViewData();
            var keywords =
                DataContainer.Read<ICollection<Keyword>>(PresetValues.SessionKeys.SetupWizardKeywords) ??
                Enumerable.Empty<Keyword>();
            return View(keywords);
        }

        protected void LoadKeywordSettingViewData()
        {
            var keywordTemplates = Enumerable.Empty<KeywordTemplate>();
            var keywordCookie = Request.Cookies["SetupWizrd_Keywords"];
            if (keywordCookie != null && !string.IsNullOrWhiteSpace(keywordCookie.Value))
            {
                try
                {
                    var keywordsInCookie =
                        JsonConvert.DeserializeObject<string[]>(Server.UrlDecode(keywordCookie.Value));
                    keywordTemplates =
                        keywordTemplates.Concat(keywordsInCookie.Select(p => new KeywordTemplate {KeywordName = p}));
                }
                catch {}//此处是为了防止转换json出错，keywordCookie.Value有可能有问题
            }
            ViewData["Keywords"] = keywordTemplates;
            var protocolsInDb = DataProvider.ProtocolsService.GetAllModels().ToList();
            var supportProtocols = SupportUtility.GetSupportProtocols();
            var protocols = protocolsInDb.Any()
                                ? supportProtocols.Where(p => protocolsInDb.Any(m => m.ProtocolType == p.Name)).ToList()
                                : supportProtocols;
            ViewData["Protocols"] = protocols;
            ViewBag.Step = Step;
        }

        [HttpPost]
        public ActionResult KeywordSetting(ICollection<Keyword> keywordModels, string preSubmit)
        {
            if (ModelState.IsValid)
            {
                if (!string.IsNullOrWhiteSpace(preSubmit))
                {
                    StepIndex -= 1;
                    DataContainer.Add(PresetValues.SessionKeys.SetupWizardKeywords, keywordModels);
                    return RedirectToAction("CaseAndTask");
                }
                var setupWizard = DataContainer.Read<SetupWizard>(PresetValues.SessionKeys.SetupWizard);
                long caseId = DataContainer.Read<long>(PresetValues.SessionKeys.SetupWizardCaseId);
                string taskName = DataContainer.Read<string>(PresetValues.SessionKeys.SetupWizardTaskName);
                var taskStatus = TaskStatusType.Running;
                var task = new Task
                    {
                        CaseId = caseId,
                        Name = taskName,
                        CreateUserId = CurrentUser.Id,
                        TaskStatus = taskStatus
                    };
                setupWizard.CreateUserId = CurrentUser.Id;
                var serviceResult = DataProvider.SetupWizardService.Save(setupWizard, caseId, task, keywordModels);
                if (serviceResult.ExecutedSuccess)
                {
                    var actionXmlUtility = ActionXmlUtility.Instance;
                    var rootEle = actionXmlUtility.CreateActionRootElement();
                    var infoEle = actionXmlUtility.CreateInfoElement(caseId, task.Id);
                    var setActionStartEle = actionXmlUtility.CreateSetActionStatusElement(taskStatus);
                    var splitKeywords =
                        SplitKeywords(DataProvider.KeywordService.GetAllModels(false, p => p.TaskId == task.Id),
                                      SupportUtility.GetSupportProtocols());
                    var keywordsEle =
                        actionXmlUtility.CreateKeywordsElement(splitKeywords);
                    var lineEle = actionXmlUtility.CreateLineElement(setupWizard.LineType, setupWizard.LineMethod,
                                                                     setupWizard.PcapPath);
                    var trojanEle = actionXmlUtility.CreateVirusEmbedInfoElement(null, null, null, null, null);
                    var qqMonitorEle = actionXmlUtility.CreateQQMonitorElement(null, null, null, null);

                    var monitorSt = DataProvider.MonitorSettingService.GetFirstMonitorSetting();
                    var protocols = DataProvider.ProtocolsService.GetAllModels().Select(p => p.ProtocolType).ToArray();
                    var monitorEle = actionXmlUtility.CreateMonitorSettingElement(monitorSt, protocols);

                    var wlEle = actionXmlUtility.CreateWhiteListElement(null);

                    var alertModels =
                        DataProvider.AlertSettingService.GetAllModels(true)
                                    .GroupBy(p => p.AlertType)
                                    .Select(p => p.FirstOrDefault()).ToArray();
                    var alertEles = actionXmlUtility.CreateAlertElement(alertModels);
                    bool sendSucc =
                        Connector.SendAction(
                            actionXmlUtility.GeneratorActionXml(rootEle, infoEle, setActionStartEle, keywordsEle,
                                                                lineEle, qqMonitorEle, trojanEle, wlEle, monitorEle,
                                                                alertEles),
                            PresetValues.MonitorIp, PresetValues.MonitorPort);
                    if (sendSucc)
                    {
                        DataContainer.Remove(PresetValues.SessionKeys.SetupWizard);
                        DataContainer.Remove(PresetValues.SessionKeys.SetupWizardCaseId);
                        DataContainer.Remove(PresetValues.SessionKeys.SetupWizardTaskName);
                        DataContainer.Remove(PresetValues.SessionKeys.SetupWizardKeywords);
                        DataContainer.Remove(PresetValues.SessionKeys.SetupWizardStep);
                        //清除缓存中当前任务和当前案件
                        CacheContainer.Clear();
                        Response.Cookies.Add(new HttpCookie("SetupWizrd_Keywords")
                            {
                                Expires = DateTime.Now.AddYears(-1),
                                Value = string.Empty
                            });
                        return RedirectToAction("TaskDetail", "Task");
                    }
                    ModelState.AddModelError("", Resources.MessageResource.SendActionError);
                }
                ModelState.AddModelError("", serviceResult.Message);
            }
            ModelState.AddModelError("", Resources.MessageResource.Save_Error);
            LoadKeywordSettingViewData();
            return View(keywordModels);
        }

        public ActionResult GeneratorKeywordHtml(Keyword keyword)
        {
            return PartialView("_SingleKeyword", keyword);
        }

        [HttpPost]
        public ActionResult GetKeywordsFromTemplate()
        {
            var keywords = DataProvider.KeywordService.GetAllKeywordsInTemplate() ??
                           Enumerable.Empty<KeywordTemplate>();
            return Json(keywords);
        }

        public ActionResult GetDisplayFields(string[] protocols)
        {
            if (protocols == null || !protocols.Any())
                return new EmptyResult();
            var supportProtocols = SupportUtility.GetSupportProtocols();
            return PartialView("_DisplayField", supportProtocols.Where(p => protocols.Contains(p.Name)));
        }

        private IEnumerable<Keyword> SplitKeywords(IEnumerable<Keyword> keywords, IList<SupportProtocol> supportProtocols)
        {
            var splitKeywords = new List<Keyword>();
            foreach (var keyword in keywords)
            {
                var protocols = keyword.Protocols.Split(new [] {','}, StringSplitOptions.RemoveEmptyEntries);
                var fields = keyword.Fields.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                foreach (string protocol in protocols)
                {
                    var supportProtocol = supportProtocols.FirstOrDefault(p => p.Name == protocol);
                    if (supportProtocol == null) continue;
                    string supportFields =
                        string.Join(",",
                                    supportProtocol.SupportFields.Where(p => fields.Contains(p.ActionName))
                                                   .Select(p => p.ActionName)
                                                   .ToArray());
                    var splitKeyword = new Keyword();
                    splitKeyword.MergeFrom(keyword);
                    splitKeyword.Protocols = protocol;
                    splitKeyword.Fields = supportFields;
                    splitKeywords.Add(splitKeyword);
                }
            }
            return splitKeywords;
        }  
    }
}
